#include "lifeLampsControl.h"
#define TARGET_FREQ WS2811_TARGET_FREQ
#define DMA         10
#define STRIP_TYPE  WS2811_STRIP_GRB

LifeLampsControl::LifeLampsControl()
{

}

LifeLampsControl::~LifeLampsControl(void)
{
    clearAll();//取消所有显示
    lifeLamps->ws2811_fini(ledstring);
    delete ledstring;
    ledstring = nullptr;
    delete lifeLamps;
    lifeLamps = nullptr;
    if (lifeLampsControlList.size() != 0)
    {
        lifeLampsControlList.clear();//清空容器
    }
    KillThread = true;
}



void LifeLampsControl::init(unsigned char pin_LED, unsigned int numLED)
{
    ledstring = new ws2812b::ws2811_t;
    ledstring->freq = TARGET_FREQ;
    ledstring->dmanum = DMA;
    ws2812b::ws2811_channel_t temp_s2811_channel_t;
    temp_s2811_channel_t.gpionum = pin_LED;
    temp_s2811_channel_t.invert = 0;    //是否反转输入,否
    temp_s2811_channel_t.count = numLED;
    temp_s2811_channel_t.strip_type = STRIP_TYPE;   //描述: LED 条带的颜色布局，使用 WS2811_STRIP_xxx 常量之一。这些常量定义了 LED 条带的 RGB 颜色顺序。
    temp_s2811_channel_t.brightness = 255;
    ledstring->channel[0] = temp_s2811_channel_t; // 此处浅拷贝没问题
    // ledstring->channel[1] = ws2811_channel_t(0,0,0,STRIP_TYPE,0); // 没用
    lifeLamps = new ws2812b::ws2811(); // 新建ws2812b的控制对象
    ws2812b::ws2811_return_t ret;
    if ((ret = lifeLamps->ws2811_init(ledstring)) != ws2812b::WS2811_SUCCESS)
    {
        // fprintf(stderr, "ws2811_init failed: %s\n", lifeLamps.ws2811_get_return_t_str(ret));
        LOG(ERROR) << "ws2811_render failed: " << lifeLamps->ws2811_get_return_t_str(ret);
        return;
    }
    isInit = true;//初始化成功了
    testDemo();//发送测试程序
    clearAll(); //先清除所有显示，
    ReInit = true;//控制线程需要初始化
    KillThread = false;
    std::thread controlLamps_th(&LifeLampsControl::controlLampsThread, this);
    controlLamps_th.detach();
}

bool LifeLampsControl::insertData(int n,LifeLampStruct & lls)
{
    auto index = lifeLampsControlList.begin();
    for(;index != lifeLampsControlList.end();index++)
    {
        if (index->n == n-1)
        {
            lifeLampsControlList.insert((++index),lls);
        }
    }
    return true;
}


void printLifeLampStruct(LifeLampStruct & lifeLS)
{
    LOG(DEBUG) << "n = " << (int)lifeLS.n << ",t = " << (int)lifeLS.time << std::hex << ",L1 = " << lifeLS.lamps[0] \
    << ",L2 = "<< lifeLS.lamps[1]  << ",L3 = " << lifeLS.lamps[2]  << ",L4 = " << lifeLS.lamps[3]\
    << ",L5 = " << lifeLS.lamps[4] << std::dec;
}


void LifeLampsControl::decodeJsonList(Json::Value lifeLampsList, bool IsLoopEnable)
{
    if (!isInit)//如果没有初始化成功
    {
        LOG(ERROR) << "ws2812b failed: never Init ,cann't decodeJsonList";
        return ;
    }
    //先判断线程是否在运行，如果在运行的话，就停止
    ws2812bMutex.lock();
    lifeLampsControlList.clear();//清空List
    size_t ListSize = lifeLampsList.size();
    for(size_t i = 0; i < ListSize; i++){
        Json::Value lamp = lifeLampsList[i];
        LifeLampStruct tempLamps;
        int L1,L2,L3,L4,L5,T,n;
        if (lamp.isMember("L1")){
            L1 = lamp["L1"].asInt();
            tempLamps.lamps[0] = static_cast<ws2812b::ws2811_led_t>(L1);
        }
        if (lamp.isMember("L2")){
            L2 = lamp["L2"].asInt();
            tempLamps.lamps[1] = static_cast<ws2812b::ws2811_led_t>(L2);
        }
        if (lamp.isMember("L3")){
            L3 = lamp["L3"].asInt();
            tempLamps.lamps[2] = static_cast<ws2812b::ws2811_led_t>(L3);
        }
        if (lamp.isMember("L4")){
            L4 = lamp["L4"].asInt();
            tempLamps.lamps[3] = static_cast<ws2812b::ws2811_led_t>(L4);
        }
        if (lamp.isMember("L5")){
            L5 = lamp["L5"].asInt();
            tempLamps.lamps[4] = static_cast<ws2812b::ws2811_led_t>(L5);
        }
        if (lamp.isMember("T")){
            T = lamp["T"].asInt();
            tempLamps.time = T;
        }
        if (lamp.isMember("n")){
            n = lamp["n"].asInt();
            tempLamps.n = n;
        }
        if (lifeLampsControlList.empty())
        {
            lifeLampsControlList.push_back(tempLamps);
        }
        else if (lifeLampsControlList.back().n == n - 1){
            lifeLampsControlList.push_back(tempLamps);
        }
        else if (lifeLampsControlList.back().n != n - 1)
        {
            insertData(n,tempLamps);
        }
    }
    LoopEnable_cur = IsLoopEnable;//最后再修改这个
    ReInit = true;
    ws2812bMutex.unlock();
}

void LifeLampsControl::clearAll(void)
{
    if (!isInit)//如果没有初始化成功
    {
        LOG(ERROR) << "ws2812b failed: never Init ,cann't clear";
        return ;
    }
    ws2812bMutex.lock();
    int lednum = int (ledstring->channel[0].count);
    for (size_t i = 0; i < lednum; i++)
    {
        ledstring->channel[0].leds[i] = 0;
    }
    ws2812b::ws2811_return_t ret;
    //执行
    if ((ret = lifeLamps->ws2811_render(ledstring)) != ws2812b::WS2811_SUCCESS)
    {
        LOG(ERROR) << "ws2811_render failed: " << lifeLamps->ws2811_get_return_t_str(ret);
    }
    ws2812bMutex.unlock();
    LOG(INFO) << "ws2812b clear ok!";
    return ;
}

void LifeLampsControl::write2ws2812b(LifeLampStruct & lampS)
{
    for(int i = 0; i < ledstring->channel[0].count; i++)
        ledstring->channel[0].leds[i] = lampS.lamps[i];
    //执行
    ws2812b::ws2811_return_t ret;
    if ((ret = lifeLamps->ws2811_render(ledstring)) != ws2812b::WS2811_SUCCESS)
    {
        LOG(ERROR) << "ws2811_render failed: " << lifeLamps->ws2811_get_return_t_str(ret);
    }
}


void LifeLampsControl::controlLampsThread(void)
{
    LOG(INFO) << "controlLampsThread begin !";
    auto index = lifeLampsControlList.begin(); // 初始化列表的初始位置
    while(!KillThread)
    {
        if (ReInit)//需要重新初始化
        {
            ws2812bMutex.lock();
            index = lifeLampsControlList.begin();
            ws2812bMutex.unlock();
            ReInit = false;
        }
        if (lifeLampsControlList.empty())
        {
            delay(100);//等100ms
        }
        else{
            LifeLampStruct tempData;
            if (!LoopEnable_cur)//如果不循环，就删除执行后的数据
            {
                ws2812bMutex.lock();
                tempData = lifeLampsControlList.front();
                lifeLampsControlList.pop_front();//删除最前面那个
                ws2812bMutex.unlock();
                // LOG(DEBUG) << "lifeLampsControlList pop_front!";
            }
            else
            {
                ws2812bMutex.lock();
                tempData = *(index);
                if (++index == lifeLampsControlList.end())
                    index = lifeLampsControlList.begin();
                ws2812bMutex.unlock();
            }
            delay(tempData.time);
            // printLifeLampStruct(tempData);
            write2ws2812b(tempData);
        }
    }
    LOG(INFO) << "controlLampsThread exit !";
}



void LifeLampsControl::testDemo(void)
{
    Json::Value lifeLampsJ(Json::arrayValue);
    for (int i = 0; i < 17; ++i) {
        Json::Value instruction(Json::objectValue);
        instruction["n"] = i;
        instruction["T"] = 500;
        switch(i)
        {
            case 4:
                instruction["L5"] = 0x00FF00;
                instruction["L4"] = 0x00FF00;
                instruction["L3"] = 0x00FF00;
                instruction["L2"] = 0x00FF00;
                instruction["L1"] = 0x00FF00;
                break;
            case 3:
                instruction["L5"] = 0x000000;
                instruction["L4"] = 0x00FF00;
                instruction["L3"] = 0x00FF00;
                instruction["L2"] = 0x00FF00;
                instruction["L1"] = 0x00FF00;
                break;
            case 2:
                instruction["L5"] = 0x000000;
                instruction["L4"] = 0x000000;
                instruction["L3"] = 0x00FF00;
                instruction["L2"] = 0x00FF00;
                instruction["L1"] = 0x00FF00;
                break;
            case 1:
                instruction["L5"] = 0x000000;
                instruction["L4"] = 0x000000;
                instruction["L3"] = 0x000000;
                instruction["L2"] = 0x00FF00;
                instruction["L1"] = 0x00FF00;
                break;
            case 0:
                instruction["L5"] = 0x000000;
                instruction["L4"] = 0x000000;
                instruction["L3"] = 0x000000;
                instruction["L2"] = 0x000000;
                instruction["L1"] = 0x00FF00;
                break;
            case 5:
                instruction["T"] = 1000;
                instruction["L5"] = 0xFF0000;
                instruction["L4"] = 0x00FF00;
                instruction["L3"] = 0x00FF00;
                instruction["L2"] = 0x00FF00;
                instruction["L1"] = 0x00FF00;
                break;
            case 6:
                instruction["L5"] = 0xFF0000;
                instruction["L4"] = 0xFF0000;
                instruction["L3"] = 0x00FF00;
                instruction["L2"] = 0x00FF00;
                instruction["L1"] = 0x00FF00;
                break;
            case 7:
                instruction["L5"] = 0xFF0000;
                instruction["L4"] = 0xFF0000;
                instruction["L3"] = 0xFF0000;
                instruction["L2"] = 0x00FF00;
                instruction["L1"] = 0x00FF00;
                break;
            case 8:
                instruction["L5"] = 0xFF0000;
                instruction["L4"] = 0xFF0000;
                instruction["L3"] = 0xFF0000;
                instruction["L2"] = 0xFF0000;
                instruction["L1"] = 0x00FF00;
                break;
            case 9:
                instruction["L5"] = 0xFF0000;
                instruction["L4"] = 0xFF0000;
                instruction["L3"] = 0xFF0000;
                instruction["L2"] = 0xFF0000;
                instruction["L1"] = 0xFF0000;
                break;
            case 10:
                instruction["L5"] = 0x000000;
                instruction["L4"] = 0x000000;
                instruction["L3"] = 0x000000;
                instruction["L2"] = 0x000000;
                instruction["L1"] = 0x000000;
                break;
            case 11:
                instruction["L5"] = 0xFF0000;
                instruction["L4"] = 0xFF0000;
                instruction["L3"] = 0xFF0000;
                instruction["L2"] = 0xFF0000;
                instruction["L1"] = 0xFF0000;
                break;
            case 12:
                instruction["L5"] = 0x000000;
                instruction["L4"] = 0x000000;
                instruction["L3"] = 0x000000;
                instruction["L2"] = 0x000000;
                instruction["L1"] = 0x000000;
                break;
            case 13:
                instruction["L5"] = 0xFF0000;
                instruction["L4"] = 0xFF0000;
                instruction["L3"] = 0xFF0000;
                instruction["L2"] = 0xFF0000;
                instruction["L1"] = 0xFF0000;
                break;
            case 14:
                instruction["L5"] = 0x000000;
                instruction["L4"] = 0x000000;
                instruction["L3"] = 0x000000;
                instruction["L2"] = 0x000000;
                instruction["L1"] = 0x000000;
                break;
            case 15:
                instruction["L5"] = 0xFF0000;
                instruction["L4"] = 0xFF0000;
                instruction["L3"] = 0xFF0000;
                instruction["L2"] = 0xFF0000;
                instruction["L1"] = 0xFF0000;
                break;
            case 16:
                instruction["L5"] = 0x000000;
                instruction["L4"] = 0x000000;
                instruction["L3"] = 0x000000;
                instruction["L2"] = 0x000000;
                instruction["L1"] = 0x000000;
                break;
        } 
        lifeLampsJ.append(instruction);
    }
    decodeJsonList(lifeLampsJ, false);
}